package com.link4a.doms.web;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author brown
 */
public abstract class FilterBeanSupport extends GenericFilterBean {

	protected final Logger logger = LoggerFactory.getLogger(getClass());

	private final PathMatcher pathMatcher = new AntPathMatcher();
	private String exclusions;
	private List<String> exclusionList;

	public void setExclusions(String exclusions) {
		this.exclusions = exclusions;
	}

	public FilterBeanSupport() {
		super();
		addRequiredProperty("exclusions");
	}

	@Override
	protected void initFilterBean() throws ServletException {
		if (StringUtils.isBlank(exclusions)) {
			exclusionList = Collections.emptyList();
			return;
		}

		String delimiters = ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS;
		exclusionList = new ArrayList<>();

		for (String pattern : StringUtils.split(exclusions, delimiters)) {
			if (StringUtils.isNotBlank(pattern)) {
				exclusionList.add(pattern.trim());
			}
		}// end for

		if (exclusionList.isEmpty()) {
			exclusionList = Collections.emptyList();
		}

		ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
		context.getAutowireCapableBeanFactory().autowireBean(this);
	}

	@Override
	public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		if (ignore(httpRequest)) {
			chain.doFilter(request, response);
		} else {
			doFilterInternal(httpRequest, httpResponse, chain);
		}
	}

	private boolean ignore(HttpServletRequest request) {
		String path = request.getServletPath();
		for (String pattern : exclusionList) {
			if (pathMatcher.match(pattern, path)) {
				return true;
			}
		}
		
		return false;
	}

	protected abstract void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException;

}
